package com.jkb.fragment.rigger.aop;

import android.os.Bundle;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

/**
 * Using AspectJ tools reach AOP. this class is used to inject
 * {@link com.jkb.fragment.rigger.rigger.Rigger} to Activity's lifecycle and other methods.
 *
 * @author JingYeoh
 *         <a href="mailto:yangjing9611@foxmail.com">Email me</a>
 *         <a href="https://github.com/justkiddingbaby">Github</a>
 *         <a href="http://blog.justkiddingbaby.com">Blog</a>
 * @since Nov 19,2017
 */
@Aspect
public class ActivityInjection extends RiggerInjection {

  //****************PointCut***********************************

  @Pointcut("execution(android.support.v4.app.FragmentActivity+.new()) && annotatedWithPuppet()")
  public void construct() {
  }

  @Pointcut("execution(* android.support.v4.app.FragmentActivity+.onCreate(..)) && annotatedWithPuppet()")
  public void onCreate() {
  }

  @Pointcut("execution(* android.support.v4.app.FragmentActivity+.onResumeFragments(..)) && annotatedWithPuppet()")
  public void onResumeFragments() {
  }

  @Pointcut("execution(* android.support.v4.app.FragmentActivity+.onPause(..)) && annotatedWithPuppet()")
  public void onPause() {
  }

  @Pointcut("execution(* android.support.v4.app.FragmentActivity+.onResume(..)) && annotatedWithPuppet()")
  public void onResume() {
  }

  @Pointcut("execution(* android.support.v4.app.FragmentActivity+.onSaveInstanceState(..)) && annotatedWithPuppet()")
  public void onSaveInstanceState() {
  }

  @Pointcut("execution(* android.support.v4.app.FragmentActivity+.onDestroy(..)) && annotatedWithPuppet()")
  public void onDestroy() {
  }

  @Pointcut("execution(* android.support.v4.app.FragmentActivity+.onBackPressed(..)) && annotatedWithPuppet()")
  public void onBackPressed() {
  }

  //****************Process***********************************

  @Around("construct()")
  public Object constructProcess(ProceedingJoinPoint joinPoint) throws Throwable {
    Object result = joinPoint.proceed();
    Object puppet = joinPoint.getTarget();
    //Only inject the class that marked by Puppet annotation.
    Method onAttach = getRiggerMethod("onPuppetConstructor", Object.class);
    onAttach.invoke(getRiggerInstance(), puppet);
    return result;
  }

  @Around("onCreate()")
  public Object onCreateProcess(ProceedingJoinPoint joinPoint) throws Throwable {
    Object result = joinPoint.proceed();
    Object puppet = joinPoint.getTarget();
    //Only inject the class that marked by Puppet annotation.
    Object[] args = joinPoint.getArgs();

    Method onCreate = getRiggerMethod("onCreate", Object.class, Bundle.class);
    onCreate.invoke(getRiggerInstance(), puppet, args[0]);
    return result;
  }

  @Around("onResumeFragments()")
  public Object onResumeFragmentsProcess(ProceedingJoinPoint joinPoint) throws Throwable {
    Object result = joinPoint.proceed();
    Object puppet = joinPoint.getTarget();
    //Only inject the class that marked by Puppet annotation.

    Method onResumeFragments = getRiggerMethod("onResumeFragments", Object.class);
    onResumeFragments.invoke(getRiggerInstance(), puppet);
    return result;
  }

  @Around("onPause()")
  public Object onPauseProcess(ProceedingJoinPoint joinPoint) throws Throwable {
    Object result = joinPoint.proceed();
    Object puppet = joinPoint.getTarget();
    //Only inject the class that marked by Puppet annotation.

    Method onPause = getRiggerMethod("onPause", Object.class);
    onPause.invoke(getRiggerInstance(), puppet);
    return result;
  }

  @Around("onResume()")
  public Object onResumeProcess(ProceedingJoinPoint joinPoint) throws Throwable {
    Object result = joinPoint.proceed();
    Object puppet = joinPoint.getTarget();
    //Only inject the class that marked by Puppet annotation.

    Method onPause = getRiggerMethod("onResume", Object.class);
    onPause.invoke(getRiggerInstance(), puppet);
    return result;
  }

  @Around("onSaveInstanceState()")
  public Object onSaveInstanceStateProcess(ProceedingJoinPoint joinPoint) throws Throwable {
    Object result = joinPoint.proceed();
    Object puppet = joinPoint.getTarget();
    //Only inject the class that marked by Puppet annotation.
    Object[] args = joinPoint.getArgs();

    Method onSaveInstanceState = getRiggerMethod("onSaveInstanceState", Object.class, Bundle.class);
    onSaveInstanceState.invoke(getRiggerInstance(), puppet, args[0]);
    return result;
  }

  @Around("onDestroy()")
  public Object onDestroyProcess(ProceedingJoinPoint joinPoint) throws Throwable {
    Object result = joinPoint.proceed();
    Object puppet = joinPoint.getTarget();
    //Only inject the class that marked by Puppet annotation.

    Method onDestroy = getRiggerMethod("onDestroy", Object.class);
    onDestroy.invoke(getRiggerInstance(), puppet);
    return result;
  }

  @Around("onBackPressed()")
  public Object onBackPressedProcess(ProceedingJoinPoint joinPoint) throws Throwable {
//    Object result = joinPoint.proceed();
    Object puppet = joinPoint.getTarget();
    //Only inject the class that marked by Puppet annotation.

    Method onBackPressed = getRiggerMethod("onBackPressed", Object.class);
    return onBackPressed.invoke(getRiggerInstance(), puppet);
  }
}
